//! 根据设定模板，读取excel数据，来生成对应的方法文件，方便读取固定的数。这里的游戏数据是无法进行热更的游戏数据。
//! excel文件需要策划在与程序员商量后自动生成
//! 模块提供了excel宏用来解析excel然后生成，样板如下
//! ```
//! excel!(
//!    // excel所在的位置
//!    "",
//!    // 生成的Rust文件位置
//!    "",
//!    // excel名字，这个也会作为生成的Rust文件的名字
//!    "exc";
//!     // 每个table对应excel文件的sheet
//!     @table "Sheet1" (
//!         // 列，用来解析sheet的列
//!         @col (
//!             // 列id,列名（对应sheet中列的名字，暂时无作用）,列的数据类型
//!             id,"id",i32;
//!             name,"name",i32;
//!         );
//!         // 该sheet表所生成的方法
//!         @method  (
//!             // 方法签名,方法输入参数,方法输出的列,方法返回的列,生成方法的模板（目前只有normal一种）
//!             "get(id:i32)->i32",(id),(name),normal;
//!             "set(name:i32)->i32",(name),(id),normal;
//!             "test(id:i32,name:i32)->i32",(id,name),(id),normal;
//!         );
//!     );
//!);
//! ```
//!在扫描之前需要设置需要进行扫描的excel文件所在文件夹和生成的Rust文件所应该防止的位置
//!

#[macro_export]
macro_rules! excel {
    (@replace_expr $_t:tt,$expr:expr)=>{
        $expr
    };
    (@table_analyze
        mut $excel:expr;
        mut $file:expr;
    )=>{
    };
     (@table_analyze
        mut $workbook:expr;
        mut $file:expr;
        @table $tname:tt (
           @col (
                $($id:ident,$name:expr,$ty:ty);*$(;)*
           );
           @method  (
                $($mname:expr,($($marg:ident),*),($($mreturn:ident),*),$mty:expr);*$(;)*
           );
        );
        // 额外
        $($body:tt)*
    ) => {
        // 读出所有的行
        let range = calamine::Reader::worksheet_range(&mut $workbook, $tname).
            ok_or(calamine::Error::Msg("Cannot find 'sheet1'")).unwrap().unwrap();

        // 每次生成一个方法都需要重新遍历一次
        let mut iter = calamine::RangeDeserializerBuilder::new().from_range(&range).unwrap();
        // 方法内容缓存
        let mut content_vec=vec![];
        // 方法名缓存
        let mut mname_vec=vec![];
        // 方法参数和返回个数存储
        let mut vec=vec![];
        // 初始化
        $(
            content_vec.push(String::new());
            mname_vec.push($mname);
            let (mut n,mut m)=(0,0);
            $(
                n+=excel!(@replace_expr ($marg),1);
            )*
            $(
                m+=excel!(@replace_expr ($mreturn),1);
            )*
            println!("{} 个数 {} {}",$mname,n,m);
            vec.push((n,m));
        )*

        // 根据方法来进行生成
        while let Some(content)=iter.next(){
            let ($($id),*):($($ty),*)=content.unwrap();
            let mut iter=vec.iter();
            let mut content_iter=content_vec.iter_mut();
            // 生成方法
            $(
                let mut content=String::from("");
                let (pindex,lindex)=iter.next().unwrap();
                $(
                    content+=$marg.to_string().as_str();
                    content+=",";
                )*
                content.pop();
                // 如果输入参数不止一个
                if *pindex!=1{
                    content="\t\t(".to_string()+&content+")";
                }else{
                    content="\t\t".to_string()+&content;
                }
                content+=" => ";
                $(
                    content+=$mreturn.to_string().as_str();
                    content+=",";
                )*
                content.pop();
                if *lindex!=1{
                   content="(".to_string()+&content+")";
                }
                content+=",\n";
                let tmp=content_iter.next().unwrap();
                *tmp+=content.as_str();
                n+=1;
            )*
        }
        // 内容写入文件
        for ((mname,mcontent),(pindex,_)) in mname_vec.into_iter()
            .zip(content_vec.into_iter())
            .zip(vec.into_iter()){
            // 获取方法参数
            let vec=mname.split(|c|{c=='('||c==')'}).collect::<Vec<&str>>();
            let vec=vec[1].split(|c|{c==':'||c==','}).collect::<Vec<&str>>();
            let mut arg=String::new();
            let len=vec.len();
            vec.into_iter().step_by(2).for_each(
                |c|{
                    arg+=c;
                    arg+=",";
                }
            );
            arg.pop();
            let content=
                if pindex!=1{
                   format!(
                        "fn {} {{ \n \
                            \tmatch ({}) {{\n\
                            {}\
                            \t\t_ => {{}}\n\
                            \t}}\n\
                        }}\n\n",
                    mname,arg,mcontent)
                }else{
                    format!(
                       "fn {} {{ \n \
                            \tmatch {} {{\n\
                            {}\
                            \t\t_ => {{}}\n\
                            \t}}\n\
                        }}\n\n",
                        mname,arg,mcontent)
                };

            std::io::Write::write(&mut $file, content.as_bytes());
        }

        excel!(@table_analyze mut $workbook;mut $file;$($body)*);
    };

    // 每一个表除了名字，接下来就应该是子表的定义
    ($excel_path:expr,$generate_path:expr,$name:expr;$($body:tt)*) => {
        let path=unsafe{
            format!("{}{}.xlsx",$excel_path,$name)
        };
        let generator_path=unsafe{
            format!("{}{}.rs",$generate_path,$name)
        };
        let error_info=format!("create {} fail",generator_path.clone());
        let mut file=std::fs::File::create(generator_path).expect(error_info.as_str());
        let mut workbook: calamine::Xlsx<_> = calamine::open_workbook(path).unwrap();

        excel!(@table_analyze mut workbook;mut file;$($body)*);
    };

}

